package com.ldgk.pim.client.view.components;

import java.util.ArrayList;


import java.util.List;


import com.extjs.gxt.ui.client.Style.HorizontalAlignment;
import com.extjs.gxt.ui.client.data.BeanModel;
import com.extjs.gxt.ui.client.event.ButtonEvent;
import com.extjs.gxt.ui.client.event.SelectionListener;
import com.extjs.gxt.ui.client.store.ListStore;
import com.extjs.gxt.ui.client.store.Record;
import com.extjs.gxt.ui.client.widget.ContentPanel;
import com.extjs.gxt.ui.client.widget.LayoutContainer;
import com.extjs.gxt.ui.client.widget.button.Button;
import com.extjs.gxt.ui.client.widget.form.CheckBox;
import com.extjs.gxt.ui.client.widget.form.ComboBox;
import com.extjs.gxt.ui.client.widget.form.DateField;
import com.extjs.gxt.ui.client.widget.form.NumberField;
import com.extjs.gxt.ui.client.widget.form.TextField;
import com.extjs.gxt.ui.client.widget.form.ComboBox.TriggerAction;
import com.extjs.gxt.ui.client.widget.grid.CellEditor;
import com.extjs.gxt.ui.client.widget.grid.CheckColumnConfig;
import com.extjs.gxt.ui.client.widget.grid.ColumnConfig;
import com.extjs.gxt.ui.client.widget.grid.ColumnModel;
import com.extjs.gxt.ui.client.widget.grid.Grid;
import com.extjs.gxt.ui.client.widget.grid.RowEditor;
import com.extjs.gxt.ui.client.widget.grid.EditorGrid.ClicksToEdit;
import com.extjs.gxt.ui.client.widget.layout.FitLayout;
import com.extjs.gxt.ui.client.widget.toolbar.SeparatorToolItem;
import com.extjs.gxt.ui.client.widget.toolbar.ToolBar;
import com.google.gwt.i18n.client.DateTimeFormat;
import com.google.gwt.user.client.Element;
import com.ldgk.pim.client.view.components.icons.Icons;

public abstract class CustomGridContainer extends LayoutContainer {
	private final List<BeanModel> deletedRecords = new ArrayList<BeanModel>();
	private final ListStore<BeanModel> gridStore = new ListStore<BeanModel>();

	private final ContentPanel cp = new ContentPanel();

	/**
	 * Default constructor
	 * @param heading - the page heading
	 */
	public CustomGridContainer(String heading){
		cp.setHeading(heading);
	}
	
	@Override
	protected void onRender(Element parent, int index) {
		super.onRender(parent, index);
		setLayout(new FitLayout());
		cp.setIcon(Icons.ICONS.table());
		cp.setFrame(true);
		cp.setLayout(new FitLayout());

		//Grid itself
		final RowEditor<BeanModel> re = new RowEditor<BeanModel>();
		re.setClicksToEdit(ClicksToEdit.TWO);

		ColumnModel cm = new ColumnModel(buildGridColumnConfig());
		final Grid<BeanModel> grid = new Grid<BeanModel>(gridStore,cm);
		grid.setBorders(true);
		grid.addPlugin(re);

		
		/** Rollback button */
		cp.setButtonAlign(HorizontalAlignment.CENTER);
		cp.addButton(new Button("Desfazer", new SelectionListener<ButtonEvent>() {
			@Override
			public void componentSelected(ButtonEvent ce) {
				gridStore.rejectChanges();
				for(BeanModel data:deletedRecords){
					gridStore.add(data);
				}
				deletedRecords.clear();
			}
		}));
		
		/** Commit button */
		cp.addButton(new Button("Aplicar", new SelectionListener<ButtonEvent>() {
			@Override
			public void componentSelected(ButtonEvent ce) {
				//If we have deleted records, invoke the method to handle them
				if( deletedRecords.size() > 0 ){
					//Delegate the delete operation
					try{
						recordsDeleted(deletedRecords);
					}catch(Exception ex){
						ex.printStackTrace();
					}
				}
				
				//Adicionar/atualizar
				List<Record> modifiedRecords = gridStore.getModifiedRecords();
				if( modifiedRecords.size() > 0 ){
					List<BeanModel> modified = new ArrayList<BeanModel>();
					for(Record r:modifiedRecords){
						modified.add((BeanModel)r.getModel());
					}

					//Delegate the update operation
					try{
						recordsCreatedOrChanged(modified);
						gridStore.commitChanges();
						deletedRecords.clear();
					}catch(Exception ex){
						ex.printStackTrace();
					}
				}
			}
		}));

		this.buildToolBar(grid,re);
		
		cp.add(grid);
		grid.setHeight(150);
		//grid.setAutoHeight(true);
		grid.setAutoWidth(true);
		cp.setAutoHeight(true);
		cp.setAutoWidth(true);
		//cp.setScrollMode(Scroll.NONE);
		//cp.setBorders(true);
		add(cp);
	}


	private void buildToolBar(final Grid<BeanModel> grid, final RowEditor<BeanModel> re){
		ToolBar toolBar = new ToolBar();  
		Button add = new Button("Nova", Icons.ICONS.add(),new SelectionListener<ButtonEvent>() {
			public void componentSelected(ButtonEvent ce) {
				BeanModel newModel = newModelInstance();
				re.stopEditing(false);
				gridStore.insert(newModel, 0);
				re.startEditing(gridStore.indexOf(newModel), true);
			}

		});
	    Button delete = new Button("Excluir Selec.", Icons.ICONS.delete(),new SelectionListener<ButtonEvent>() {
			public void componentSelected(ButtonEvent ce) {
				List<BeanModel> selectedItens = grid.getSelectionModel().getSelectedItems();				
				for(BeanModel data:selectedItens){
					deletedRecords.add(data);
					gridStore.remove(data);
				}
			}
		});
	    Button refresh = new Button("Atualizar", Icons.ICONS.refresh(),new SelectionListener<ButtonEvent>() {
			@Override
			public void componentSelected(ButtonEvent ce) {
				try{
					loadData(gridStore);
				}catch(Exception ex){
					ex.printStackTrace();
				}
			}
		});
		
		toolBar.add(add);  
	    toolBar.add(new SeparatorToolItem());  
	    toolBar.add(delete);
	    toolBar.add(new SeparatorToolItem());  
	    toolBar.add(refresh);
	    toolBar.add(new SeparatorToolItem());  
	    cp.setTopComponent(toolBar);  
	}
	
	protected CheckColumnConfig buildCheckboxConfig(String fieldId, String header, int width){
	    CheckColumnConfig checkColumn = new CheckColumnConfig(fieldId,header,width);
	    CellEditor editor = new CellEditor(new CheckBox());    	
	    checkColumn.setEditor(editor);  
	    return checkColumn;
	}
	
	protected ColumnConfig buildNumberConfig(String id, String header, int width, Class numberClass){
		ColumnConfig config = new ColumnConfig();
	    config.setId(id);
	    config.setHeader(header);
	    config.setWidth(width);
	    
	    NumberField field = new NumberField();
	    field.setPropertyEditorType(numberClass);
	    config.setEditor(new CellEditor(field));
	    return config;
	}
	
	protected ColumnConfig buildComboBoxConfig(String fieldId, String header, String comboIdField, String comboDisplayField, ListStore<BeanModel> store){
		//Build editor
		ComboBox<BeanModel> combo = new ComboBox<BeanModel>();
		combo.setAllowBlank(false);
		combo.setForceSelection(true);
		combo.setEditable(false);
		combo.setTriggerAction(TriggerAction.ALL);
		combo.setDisplayField(comboDisplayField);
		combo.setValueField(comboIdField);
		combo.setStore(store);

		CellEditor editor = new CellEditor(combo){
			@Override
			public Object preProcessValue(Object name) {
				return name;
			}
			@Override
			public Object postProcessValue(Object value) {
				return value;
			}
		}; 
		
		//Build column config
		ColumnConfig column = new ColumnConfig();
		column.setId(fieldId);
		column.setHeader(header);
		column.setWidth(115);
		column.setEditor(editor);

		return column;
	}
	
	protected ColumnConfig buildDateConfig(String id, String header, int width){
		DateField dateField = new DateField();
		dateField.getPropertyEditor().setFormat(DateTimeFormat.getFormat("dd/MM/y"));

		ColumnConfig config = new ColumnConfig();
		config.setEditor(new CellEditor(dateField));
		config.setDateTimeFormat(DateTimeFormat.getFormat("dd/MM/y"));
		config.setId(id);
		config.setHeader(header);
		config.setWidth(width);
		return config;
	}
	
	protected ColumnConfig buildTextFieldConfig(String id, String header, int width){
		ColumnConfig config = new ColumnConfig();
	    config.setId(id);
	    config.setHeader(header);
	    config.setWidth(width);
		TextField<String> txt = new TextField<String>();
		config.setEditor(new CellEditor(txt));
	    return config;
	}
	
	protected abstract BeanModel newModelInstance();
	protected abstract void recordsDeleted(List<BeanModel> list) throws Exception;
	protected abstract void recordsCreatedOrChanged(List<BeanModel> list) throws Exception;
	protected abstract void loadData(ListStore<BeanModel> gridStore) throws Exception;
	protected abstract List<ColumnConfig> buildGridColumnConfig();
}